package com.cloud.rou.im.server;

import com.google.common.base.Preconditions;
import jdk.nashorn.internal.ir.annotations.Immutable;

import java.util.concurrent.TimeUnit;



/**
 * <p></p>
 *
 * @author GaoShuangWen
 * @since 2019-11-15 19:02
 */
public final class StopStrategies {
    private static final StopStrategy NEVER_STOP = new StopStrategies.NeverStopStrategy();

    private StopStrategies() {
    }

    public static StopStrategy neverStop() {
        return NEVER_STOP;
    }

    public static StopStrategy stopAfterAttempt(int attemptNumber) {
        return new StopStrategies.StopAfterAttemptStrategy(attemptNumber);
    }

    /** @deprecated */
    @Deprecated
    public static StopStrategy stopAfterDelay(long delayInMillis) {
        return stopAfterDelay(delayInMillis, TimeUnit.MILLISECONDS);
    }

    public static StopStrategy stopAfterDelay(long duration, TimeUnit timeUnit) {
        Preconditions.checkNotNull(timeUnit, "The time unit may not be null");
        return new StopStrategies.StopAfterDelayStrategy(timeUnit.toMillis(duration));
    }

    @Immutable
    private static final class StopAfterDelayStrategy implements StopStrategy {
        private final long maxDelay;

        public StopAfterDelayStrategy(long maxDelay) {
            Preconditions.checkArgument(maxDelay >= 0L, "maxDelay must be >= 0 but is %d", new Object[]{maxDelay});
            this.maxDelay = maxDelay;
        }

        public boolean shouldStop(Attempt failedAttempt) {
            return failedAttempt.getDelaySinceFirstAttempt() >= this.maxDelay;
        }
    }

    @Immutable
    private static final class StopAfterAttemptStrategy implements StopStrategy {
        private final int maxAttemptNumber;

        public StopAfterAttemptStrategy(int maxAttemptNumber) {
            Preconditions.checkArgument(maxAttemptNumber >= 1, "maxAttemptNumber must be >= 1 but is %d", new Object[]{maxAttemptNumber});
            this.maxAttemptNumber = maxAttemptNumber;
        }

        public boolean shouldStop(Attempt failedAttempt) {
            return failedAttempt.getAttemptNumber() >= (long)this.maxAttemptNumber;
        }
    }

    @Immutable
    private static final class NeverStopStrategy implements StopStrategy {
        private NeverStopStrategy() {
        }

        public boolean shouldStop(Attempt failedAttempt) {
            return false;
        }
    }
}
